package io.xxx.omni.sync.impl

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import io.xxx.omni.sync.Document
import io.xxx.omni.sync.PagePorter
import io.xxx.omni.sync.Store
import io.xxx.omni.util.dateTimeFormatter
import io.xxx.omni.util.toLocalDateTime
import org.apache.commons.codec.digest.DigestUtils
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import org.springframework.web.util.UriComponentsBuilder
import java.time.LocalDateTime
import java.util.*

/**
 * 抖音
 */
abstract class DyPorter : PagePorter() {

    val httpUrl = "https://openapi-fxg.jinritemai.com/"

    override val platformCode = "douyin"

    protected abstract val method: String

    protected fun getResponse(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        orderBy: String,
        pageNo: Long = 1,
    ): JSONObject {
        val timestamp = LocalDateTime.now().format(dateTimeFormatter)
        val v = "2"
        val params = getParams(startTime, endTime, pageNo, orderBy)
        val signMap = TreeMap(params)
        val builder = StringBuilder().append(store.appSecret)
            .append("app_key").append(store.appKey)
            .append("method").append(method)
            .append("param_json").append(JSON.toJSONString(params))
            .append("timestamp").append(store.accessToken)
            .append("v").append(v)
            .append(store.appSecret)
        val sign = DigestUtils.md5Hex(builder.toString())
        val url = UriComponentsBuilder.fromHttpUrl(httpUrl)
            .path(method.replace(".", "/"))
            .queryParam("method", method)
            .queryParam("app_key", store.appKey)
            .queryParam("access_token", store.accessToken)
            .queryParam("param_json", JSON.toJSONString(params))
            .queryParam("timestamp", timestamp)
            .queryParam("v", v)
            .queryParam("sign", sign)
            .toUriString()

        val response = restTemplate.getForEntity(url, JSONObject::class.java)
        if (response.statusCode.isError || response.body == null) {
            val msg = "接口[method: $method, queryParams: $signMap]异常"
            throw RuntimeException(msg)
        }
        val body = response.body!!
        if (body.getInteger("err_no") != 0) {
            val msg = "接口[method: $method, queryParams: $signMap]异常: $body"
            log.error(msg)
            throwException(method, null, body.getString("message"))
        }
        return response.body!!.getJSONObject("data")
    }

    private fun getParams(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long = 1,
        orderBy: String
    ): Map<String, String> {
        return TreeMap(
            mapOf(
                "is_desc" to "1",
                "order_by" to orderBy,
                "start_time" to startTime.format(dateTimeFormatter),
                "end_time" to endTime.format(dateTimeFormatter),
                "page" to pageNo.toString(),
                "size" to pageSize.toString(),
            )
        )
    }

    companion object {
        private val log = LoggerFactory.getLogger(DyPorter::class.java)
    }
}

@Component
class DyTradePorter : DyPorter() {

    // https://op.jinritemai.com/docs/api-docs/15/55
    override val method = "order.list"

    override val jobId = 1

    override fun getParameters(store: Store): List<Any> {
        return listOf("update_time")
    }

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long? {
        val response = getResponse(store, startTime, endTime, parameter as String)
        return response.getLong("total")
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long,
    ): List<Document>? {
        val response = getResponse(store, startTime, endTime, parameter as String)
        return response.getJSONArray("list").map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            Document(
                value.getString("order_id"),
                value,
                value.getString("update_time").toLocalDateTime()
            )
        }
    }
}

@Component
class DyTradeProcurator : DyTradePorter() {

    override val jobId = 3

    override val cron = "0/10 * * * * ?"

    override fun getParameters(store: Store): List<Any> {
        return listOf("create_time")
    }
}

@Component
class DyRefundPorter : DyPorter() {

    // https://op.jinritemai.com/docs/api-docs/17/80
    override val method = "refund.orderList"

    override val jobId = 1

    override fun getParameters(store: Store): List<Any> {
        return listOf("update_time")
    }

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long? {
        val response = getResponse(store, startTime, endTime, parameter as String)
        return response.getLong("total")
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long,
    ): List<Document>? {
        val response = getResponse(store, startTime, endTime, parameter as String)
        return response.getJSONArray("list").map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            Document(
                value.getString("aftersale_id"),
                value.getString("order_id"),
                value,
                value.getString("update_time").toLocalDateTime()
            )
        }
    }
}

@Component
class DyRefundProcurator : DyRefundPorter() {

    override val jobId = 4

    override val cron = "0/10 * * * * ?"

    override fun getParameters(store: Store): List<Any> {
        return listOf("apply_time")
    }
}